/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package org.jfonia.view.elements;

import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import org.jfonia.connect5.basics.BasicValueNode;
import org.jfonia.connect5.basics.MutableValueNode;
import org.jfonia.connect5.basics.ValueNode;
import org.jfonia.connect5.basics.Observer;
import org.jfonia.connect5.relations.Equal;
import org.jfonia.connect5.relations.UnidirectionalEqual;
import org.jfonia.constants.ViewConstants;
import org.jfonia.view.panels.NodePanel;

/**
 * Extends the abstract class BasicNodePanel and adds observers to the
 * bounds of this component. The width and height bounds are handled
 * differently though: the width/height of the component is set to
 * the width/height of the corresponding frame, to allow the component
 * to take up as much space as possible.
 *
 * @author Rik Bauwens
 */
public class PartPanel extends NodePanel
        implements MouseListener, FocusListener
{
        private MutableValueNode<Double> frameWidth;
        private ValueNode<Double> staffHeight;

        private UnidirectionalEqual frameXRelation;
        private UnidirectionalEqual frameWidthRelation;

        private boolean selected;
        private boolean highlighted;

        public PartPanel(ValueNode<Double> frameX, ValueNode<Double> staffY,
                                 ValueNode<Double> frameWidth, MutableValueNode<Double> staffHeight)
        {
                super(new BasicValueNode<Double>(0.0), new BasicValueNode<Double>(0.0),
                      new BasicValueNode<Double>(0.0), new BasicValueNode<Double>(0.0));
                //this.frameWidth = frameWidth;
                this.frameWidth = new BasicValueNode<Double>(0.0);
                setFrameWidthNode(frameWidth);
                this.staffHeight = staffHeight;
                selected = false;
                highlighted = false;

                //Later an offset can be added here
                setFrameXNode(frameX);
                //Later an offset can be added here
                new UnidirectionalEqual<Double>(staffY, yNode);
                //MaxRelation to make sure that the width of the frame
                //is the largest width of its elements

                //new DoubleMaxRelation(frameWidth, this.widthNode);
                //MaxRelation to make sure that the height of the staff
                //is the largest height of its elements
                //new DoubleMaxRelation(staffHeight, heightNode);
                new Equal<Double>(staffHeight, heightNode);
                init();
        }

        private void init()
        {
                //Set bounds of this panel
                //As width and height, the width/height of the frame/staff is used
                setBounds(xNode.getValue().intValue(), yNode.getValue().intValue(),
                          frameWidth.getValue().intValue(), staffHeight.getValue().intValue());
                setBackground(ViewConstants.ELEMENT_COLOR);
                addMouseListener(this);
                addFocusListener(this);
                xNode.addObserver( new Observer() {
                        public void onNotify(Object source)
                        {
                                setLocation((int) xNode.getValue().intValue(), getY());
                        }
		});
		yNode.addObserver( new Observer() {
			public void onNotify(Object source)
			{
				setLocation(getX(), yNode.getValue().intValue());
			}
		});
                frameWidth.addObserver( new Observer() {
			public void onNotify(Object source)
			{
                                setBounds(getX(), getY(),
                                        frameWidth.getValue().intValue(), getHeight());
			}
		});
                staffHeight.addObserver( new Observer() {
			public void onNotify(Object source)
			{
				setBounds(getX(), getY(),
                                        getWidth(), staffHeight.getValue().intValue());
			}
		});
        }

        public boolean isSelected()
        {
                return selected;
        }

        public final void setFrameXNode(ValueNode<Double> frameXNode)
        {
                if(frameXRelation != null)
                        frameXRelation.switchOff();
                frameXRelation = new UnidirectionalEqual(frameXNode, xNode);
        }

        public final void setFrameWidthNode(ValueNode<Double> frameWidthNode)
        {
                if(frameWidthRelation != null)
                        frameWidthRelation.switchOff();
                frameWidthRelation = new UnidirectionalEqual(frameWidthNode, frameWidth);
        }

        private void setHighlighted(boolean highlighted)
        {

                if(!selected)
                {
                        if(highlighted)
                                setBackground(ViewConstants.ELEMENT_HIGHLIGHTED_COLOR);
                        else
                                setBackground(ViewConstants.ELEMENT_COLOR);
                        this.highlighted = highlighted;
                }
                else
                {
                        this.highlighted = false;
                }
        }

        protected void setSelected(boolean selected)
        {
                if(selected)
                        setBackground(ViewConstants.ELEMENT_SELECTED_COLOR);
                else
                        setBackground(ViewConstants.ELEMENT_COLOR);
                this.selected = selected;
        }

        //Handle MouseEvent
        public void mouseClicked(MouseEvent e)
        {

                //RequestFocus to show the blinking cursor
                requestFocus();
                //If the textfield is clicked once, select it
                if(e.getClickCount() == 1)
                {
                        setSelected(true);
                }
                //If the textfield is clicked twice, enable it
                //to allow a contentchange
                else if(e.getClickCount() == 2)
                {
                        setEnabled(true);
                }
        }

        public void mousePressed(MouseEvent e) {}

        public void mouseReleased(MouseEvent e) {}

        public void mouseEntered(MouseEvent e)
        {
                setHighlighted(true);
        }

        public void mouseExited(MouseEvent e)
        {
                setHighlighted(false);
        }

        public void focusGained(FocusEvent e)
        {
                //setSelected(true);
                //setEnabled(true);
        }

        //If the panels' focus is lost, disable it
        public void focusLost(FocusEvent e)
        {
                //setEnabled(false);
                //setSelected(false);
        }
}
